package ru.niir.goodfil.db.handlers;

import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.apache.commons.lang.StringUtils.isBlank;
import ru.niir.goodfil.utils.validation.*;
import ru.niir.goodfil.db.*;
import ru.niir.goodfil.exceptions.InvalidIdException;
import ru.niir.goodfil.exceptions.WrongHandlerException;

/**
 * Обработчик для пользователей
 * @see ru.niir.goodfil.db.User пользователи
 */
public class UserHandler extends Handler
{
    /**
     * Конструктор 
     */
    public UserHandler(Goodfil gf)
    {
        super(User.class, gf);
    }

    /**
     * Проверка пользователя.
     * 2. clientId - значение либо null, либо указано верно (FK)
     * 3. fio - заполнено
     * 4. login - заполнено и уникально (IDX)
     * 5. parentManagerId - значение либо null, либо указано верно (FK)
     * 6. maxDiscountPercent 0
     * 7. maxDiscountAbs 0
     * 8. Соответствие заполненых полей и roleId
     *
     * Убраны проверки:
     * 1. roleId - значение лежит допустимом диапазоне (FK)
     */
    public ValidationResult validate(Object o)
    {
        assert o != null;
        User user = (User) o;

        if (user.getClientId() != null && user.getClientId() == -1) user.setClientId(null);
        if (user.getParentManagerId() != null && user.getParentManagerId() == -1) user.setParentManagerId(null);

        ValidationResult result = ValidationResult.Ok(User.class);

        if (user.getUserRoleId() == Role.CLIENT)
        {
            if (get(Client.class,  user.getClientId()) == null)
                result.addValidationError(new ValidationError("clientId", "Идентификатор клиента", user.getClientId(), ValidationProblem.REFERENCE));
        }
        else user.setClientId(null);

        if (user.getUserRoleId() != Role.CLIENT)
        {
            if (isBlank(user.getFio())) result.addValidationError(new ValidationError("fio", "ФИО", user.getFio(), ValidationProblem.NOT_EMPTY));
        }
        else user.setFio("");

        if (isBlank(user.getLogin())) result.addValidationError(new ValidationError("login", "Логин", user.getLogin(), ValidationProblem.NOT_EMPTY));
        if (!checkUserLoginUnique(user.getLogin(), user.getId())) result.addValidationError(new ValidationError("login", "Логин", user.getLogin(), ValidationProblem.UNIQUE));

        if (user.getUserRoleId() == Role.MANAGER)
            if (user.getParentManagerId() != null && get(User.class, user.getParentManagerId()) == null)
                result.addValidationError(new ValidationError("parentManagerId", "Начальник", user.getParentManagerId(), ValidationProblem.REFERENCE));
        else user.setParentManagerId(null);

        user.setMaxDiscountAbs(0);
        user.setMaxDiscountPercent(0);

        return result;
    }

    /**
     * Пользователя можно удалить если:
     * 1. с ним не связаны заказы
     * 2. с ним не связаны замещения
     *
     * Убрано:
     * 1. он не является начальником для других пользователей (FK)
     * 2. с ним не связаны клиенты (FK)
     * @param id идентификатор объекта
     * @return
     */
    public RemoveCheckResult removeCheck(long id)
    {
        if (!exists(klass, id)) throw new InvalidIdException(klass, id);

        if (id == 1) return RemoveCheckResult.Error(User.class, User.class);

//        long items = (Long) getSession().createQuery("select count(*) from User where parentManagerId =? ").setLong(0, id).uniqueResult();
//        if (items > 0) return RemoveCheckResult.Error(User.class, User.class);

//        items = (Long) getSession().createQuery("select count(*) from Client where managerId = ?").setLong(0, id).uniqueResult();
//        if (items > 0) return RemoveCheckResult.Error(User.class, Client.class);

        long items = (Long)getSession().createQuery("select count(*) from Order where managerId=?").setLong(0, id).uniqueResult();
        if (items > 0) return RemoveCheckResult.Error(User.class, Order.class);

        items = (Long)getSession().createQuery("select count(*) from Replacement where managerId=? or assistantId=?").setLong(0, id).setLong(1, id).uniqueResult();
        if (items > 0) return RemoveCheckResult.Error(User.class, Replacement.class);

        return RemoveCheckResult.Ok(User.class);
    }

    /**
     * Действия, выполняемые перем обновлением данных о пользователе
     * @param o объект - сущность БД
     */
    public void preUpdate(Object o)
    {
        assert o != null;
        if (!(o instanceof User)) throw new WrongHandlerException(klass, o.getClass());
        User user = (User) o;

        // UNSAFE, но лучше оставить как есть)
        if (user.getClientId() != null && user.getClientId() == -1) user.setClientId(null);
        if (user.getParentManagerId() != null && user.getParentManagerId() == -1) user.setParentManagerId(null);
    }

    public void preSave(Object o)
    {
        preUpdate(o);
    }

    /**
     * Проверить уникальность логина, игнорируя объект с указанным идентификатором
     * @param login 
     * @param id идентификатор пользователя, который игнорируем при проверке
     * @return
     */
    public boolean checkUserLoginUnique(String login, long id)
    {
        assert login != null;
        login = login.trim();

        return ((Long) getSession().createQuery("select count(*) from User where login = ? and id != ?")
                .setString(0, login)
                .setLong(1, id)
                .uniqueResult()) == 0;
    }
}
